package com.atguigu.ssyx.product.service.impl;

import com.atguigu.ssyx.common.config.RedissonConfig;
import com.atguigu.ssyx.common.constant.RedisConst;
import com.atguigu.ssyx.common.exception.SsyxException;
import com.atguigu.ssyx.common.result.Result;
import com.atguigu.ssyx.common.result.ResultCodeEnum;
import com.atguigu.ssyx.model.product.SkuAttrValue;
import com.atguigu.ssyx.model.product.SkuImage;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.model.product.SkuPoster;
import com.atguigu.ssyx.mq.constant.MqConst;
import com.atguigu.ssyx.mq.service.RabbitService;
import com.atguigu.ssyx.product.mapper.SkuInfoMapper;
import com.atguigu.ssyx.product.service.SkuAttrValueService;
import com.atguigu.ssyx.product.service.SkuImageService;
import com.atguigu.ssyx.product.service.SkuInfoService;
import com.atguigu.ssyx.product.service.SkuPosterService;
import com.atguigu.ssyx.vo.product.SkuInfoQueryVo;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import com.atguigu.ssyx.vo.product.SkuStockLockVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import javafx.scene.control.Skin;
import org.checkerframework.checker.units.qual.A;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * <p>
 * sku信息 服务实现类
 * </p>
 *
 * @author lqh
 * @since 2023-09-25
 */
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements SkuInfoService {

    //商品图片表
    @Autowired
    private SkuImageService skuImageService;

    //商品的平台属性
    @Autowired
    private SkuAttrValueService skuAttrValueService;

    //宣传海报表
    @Autowired
    private SkuPosterService skuPosterService;


    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //条件分页查询Sku
    @Override
    public IPage<SkuInfo> selectPageSkuInfo(Page<SkuInfo> pageParam, SkuInfoQueryVo skuInfoQueryVo) {
        //商品类型(普通商品 还是 秒杀商品)
        String skuType = skuInfoQueryVo.getSkuType();
        //商品名称
        String keyword = skuInfoQueryVo.getKeyword();
        //商品 分类Id
        Long categoryId = skuInfoQueryVo.getCategoryId();

        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(keyword)) {
            wrapper.like(SkuInfo::getSkuName, keyword);
        }
        if (!StringUtils.isEmpty(skuType)) {
            wrapper.like(SkuInfo::getSkuType, skuType);
        }
        if (!StringUtils.isEmpty(categoryId)) {
            wrapper.eq(SkuInfo::getCategoryId, categoryId);
        }
        IPage<SkuInfo> iPage = baseMapper.selectPage(pageParam, wrapper);

        return iPage;

    }

    //添加商品sku信息
    @Override
    public void saveSkuInfo(SkuInfoVo skuInfoVo) {

        //1.添加sku的基本信息
        //将 SkuInfoVo中的值 放到 skuInfo中 父子类
        //原始方式 从vo中get 然后set到skuInfo
        //Spring中的工具类 就可以直接复制 只是找到相同属性名称 然后复制
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        baseMapper.insert(skuInfo);
        //2.保存sku海报
        List<SkuPoster> posters = skuInfoVo.getSkuPosterList();
        //判断集合是否为空
        if (!CollectionUtils.isEmpty(posters)) {
            //遍历 向每个海报对象中添加skuId
            for (SkuPoster poster : posters) {
                poster.setSkuId(skuInfo.getId());
            }
            skuPosterService.saveBatch(posters);
        }
        //3.保存图片
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            for (SkuImage images : skuImagesList) {
                //设置商品的sku
                images.setSkuId(skuInfo.getId());
            }
            skuImageService.saveBatch(skuImagesList);
        }
        //4.保存sku平台属性
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                //设置商品skuId
                skuAttrValue.setSkuId(skuInfo.getId());
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }


    }

    //根据Id查找
    @Override
    public SkuInfoVo getByIdAll(Long id) {
        SkuInfoVo skuInfoVo = new SkuInfoVo();

        //根据Id查询基本信息
        SkuInfo skuInfo = baseMapper.selectById(id);
        //图片信息
        List<SkuImage> skuImageList = skuImageService.getImageList(id);
        //海报信息
        List<SkuPoster> skuPosterList = skuPosterService.getPosterList(id);
        //id查询商品属性信息列表
        List<SkuAttrValue> skuAttrValueList = skuAttrValueService.getAttrList(id);
        //封装所有的数据
        BeanUtils.copyProperties(skuInfo, skuInfoVo);
        skuInfoVo.setSkuImagesList(skuImageList);
        skuInfoVo.setSkuPosterList(skuPosterList);
        skuInfoVo.setSkuAttrValueList(skuAttrValueList);
        return skuInfoVo;
    }

    //修改Sku
    @Override
    public void updateSkuInfo(SkuInfoVo skuInfoVo) {
        SkuInfo skuInfo = new SkuInfo();
        //修改Sku表中的基本信息
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        baseMapper.updateById(skuInfo);

        Long id = skuInfoVo.getId();
        //先删除 在添加 就是修改
        //图片信息
        LambdaQueryWrapper<SkuImage> imageWrapper = new LambdaQueryWrapper<>();
        imageWrapper.eq(SkuImage::getSkuId, id);
        skuImageService.remove(imageWrapper);
        //添加
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            for (SkuImage images : skuImagesList) {
                //设置商品的sku
                images.setSkuId(id);
            }
            skuImageService.saveBatch(skuImagesList);
        }
        //海报信息
        skuPosterService.remove(new LambdaQueryWrapper<SkuPoster>().eq(SkuPoster::getSkuId, id));

        List<SkuPoster> posters = skuInfoVo.getSkuPosterList();
        //判断集合是否为空
        if (!CollectionUtils.isEmpty(posters)) {
            //遍历 向每个海报对象中添加skuId
            for (SkuPoster poster : posters) {
                poster.setSkuId(id);
            }
            skuPosterService.saveBatch(posters);
        }

        //商品属性
        skuAttrValueService.remove(new LambdaQueryWrapper<SkuAttrValue>().eq(SkuAttrValue::getSkuId, id));
        //4.保存sku平台属性
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                //设置商品skuId
                skuAttrValue.setSkuId(id);
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }
    }

    //修改状态 商品的审核
    @Override
    public void check(Long skuId, Integer status) {
        SkuInfo skuInfo = baseMapper.selectById(skuId);
        skuInfo.setCheckStatus(status);
        baseMapper.updateById(skuInfo);
    }

    //商品上下架 使用到MQ
    @Override
    public void publish(Long skuId, Integer status) {
        if (status == 1) {
            //上架
            SkuInfo skuInfo = baseMapper.selectById(skuId);
            skuInfo.setPublishStatus(status);
            baseMapper.updateById(skuInfo);
            //TODO 后续完善 ES MQ
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
                    MqConst.ROUTING_GOODS_UPPER, skuId);

        } else {
            //下架
            SkuInfo skuInfo = baseMapper.selectById(skuId);
            skuInfo.setPublishStatus(status);
            baseMapper.updateById(skuInfo);
            //TODO 后续完善 ES MQ
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
                    MqConst.ROUTING_GOODS_LOWER, skuId);
        }
    }

    //新人专享
    @Override
    public void isNewPerson(Long id, Integer status) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(id);
        skuInfo.setIsNewPerson(status);
        baseMapper.updateById(skuInfo);
    }

    //远程调用
    //写完之后还要定义
    //引入依赖 service-product-client
    @Override
    public List<SkuInfo> findSkuInfoList(@RequestBody List<Long> skuIdList) {
        //传集合Id进行查询
        List<SkuInfo> skuInfoList = baseMapper.selectBatchIds(skuIdList);
        return skuInfoList;
    }

    //根据关键字匹配sku列表
    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        List<SkuInfo> skuInfoList = baseMapper.selectList(
                //根据名称匹配
                //接口写完 直接 要去service-client-product模块中第一定
                new LambdaQueryWrapper<SkuInfo>().like(SkuInfo::getSkuName, keyword)
        );
        return skuInfoList;
    }

    //---------------------微信小程序？？？------------------------------


    //获取新人专享商品
    @Override
    public List<SkuInfo> findNewPersonSkuInfoList() {
        //在skuInfo中查is_new_person = 1 就是新人专享
        //还要商品是否上架 publish_status=1
        //显示其中三个 显示 小程序的页面显示不下     获取第一页 每页三条记录
        Page<SkuInfo> infoPage = new Page<>(1, 3);
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        //新人专享
        wrapper.eq(SkuInfo::getIsNewPerson, 1);
        //上架
        wrapper.eq(SkuInfo::getPublishStatus, 1);
        //排序 库存降序
        wrapper.orderByDesc(SkuInfo::getStock);
        //取其中三个 前三条 两种实现方式 第一种 遍历取前三 第二种 直接分页数量取3

        //调用方法 查询
        IPage<SkuInfo> skuInfoIPage = baseMapper.selectPage(infoPage, wrapper);
        //getRecords 获取当前页面数据
        List<SkuInfo> skuInfoList = skuInfoIPage.getRecords();
        return skuInfoList;

    }

    //sku商品的详情信息-获取skuInfoVo信息
    @Override
    public SkuInfoVo getSkuInfoVo(Long skuId) {
        SkuInfoVo skuInfoVo = new SkuInfoVo();

        //根据skuId查询skuInfo
        SkuInfo skuInfo = baseMapper.selectById(skuId);

        //skuId查询sku图片
        List<SkuImage> imageList = skuImageService.getImageList(skuId);

        //skuId查询sku海报
        List<SkuPoster> posterList = skuPosterService.getPosterList(skuId);

        //skuId查询属性
        List<SkuAttrValue> attrList = skuAttrValueService.getAttrList(skuId);

        //封装
        BeanUtils.copyProperties(skuInfo, skuInfoVo);
        skuInfoVo.setSkuImagesList(imageList);
        skuInfoVo.setSkuPosterList(posterList);
        skuInfoVo.setSkuAttrValueList(attrList);
        return skuInfoVo;
    }


    //锁定库存
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {
        //1.判断集合是否空
        if (CollectionUtils.isEmpty(skuStockLockVoList)) {
            throw new SsyxException(ResultCodeEnum.DATA_ERROR);
        }

        //2.遍历 得到每个商品 验证库存 并且锁定库存 具备原子性  分布式锁
        skuStockLockVoList.stream().forEach(skuStockLockVo -> {
            this.checkLock(skuStockLockVo);
        });

        //3.只要有一个商品锁定失败 锁定成功的商品都要解锁
        boolean b = skuStockLockVoList.stream()
                //任何一个匹配到 都执行
                .anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());

        if (b) {
            //解锁
            skuStockLockVoList.stream().filter(SkuStockLockVo::getIsLock)
                    .forEach(skuStockLockVo -> {
                        baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
                    });

            return false;
        }
        //4.如果所有商品 都锁定成功了 redis缓存相关数据 为了方便后面解锁和减库存
        redisTemplate.opsForValue().set(RedisConst.SROCK_INFO + orderNo,skuStockLockVoList);
        return true;
    }

    //遍历skuStockLockVoList得到每个商品 验证库存并锁定库存 具备原子性
    //验证库存锁定
    //并发 分布式锁实现
    private void checkLock(SkuStockLockVo skuStockLockVo) {
        //获取锁 getFairLock 公平锁 在队列中等待时间最长的优先得到锁
        RLock fairLock =
                this.redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX + skuStockLockVo.getSkuId());

        //加锁
        fairLock.lock();

        try{
            //验证库存 查询数据库
            SkuInfo skuInfo =
                    baseMapper.checkStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
            //判断
            if (skuInfo == null){
                //没有满足条件的商品 设置isLock值返回 false 返回
                skuStockLockVo.setIsLock(false);
                return;
            }
            //有满足要求的商品 锁定
            //锁定库存 更新 update
            Integer rows =
                    baseMapper.lockStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
            if (rows == 1){
                skuStockLockVo.setIsLock(true);
            }
        }finally {
            //解锁 总会被执行
            fairLock.unlock();
        }
    }

    //减库存
    @Override
    public void minusStock(String orderNo) {
        //从Redis中获取锁定的库存的信息
        List<SkuStockLockVo> skuStockLockVoList =
                (List<SkuStockLockVo>) redisTemplate.opsForValue().get(RedisConst.SROCK_INFO + orderNo);

        //
        if (CollectionUtils.isEmpty(skuStockLockVoList)){
            return;
        }

        //遍历 得到每个对象 减库存
        skuStockLockVoList.forEach(skuStockLockVo -> {
            baseMapper.minusStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
        });

        //删除redis数据
        redisTemplate.delete(RedisConst.SROCK_INFO + orderNo);
    }
}
